import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Copyright © 2018胡建松. All rights reserved.
 *
 * @Package: PACKAGE_NAME
 * @author: hujiansong
 * @date: 2018/7/25 10:00
 * @version: V1.0
 */
public class Tree {
    private SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    private String currentDay = dayFormat.format(new Date()) + " ";

    Map<String, List<Node>> toMettingMap = new HashMap<>();
    Map<String, List<Node>> arriveMap = new HashMap<>();

    private static final String A_STATION = "Hakodate";
    private static final String B_STATION = "Tokyo";

    private static final String EARLY_METTING_TIME = "08:00";
    private static final String LAST_ARRIVE_TIME = "18:00";

    public Tree(List<String> nodes) {

        if (nodes == null || nodes.size() == 0) {
            throw new BizException("");
        }

        nodes.forEach(node -> {
            String[] datas = node.split(" ");
            String startStation = datas[0];
            String arrvieStation = datas[2];
            Long costPrice = Long.parseLong(datas[4]);
            Date startTime = null;
            Date arriveTime = null;
            try {
                startTime = dateFormat.parse(currentDay + datas[1]);
                arriveTime = dateFormat.parse(currentDay + datas[3]);
            } catch (ParseException e) {
                System.out.println(datas[1]);
                System.out.println(datas[3]);
                throw new BizException("日期转换失败");
            }
            Node connection = new Node();
            connection.setStartStation(startStation);
            connection.setArriveStation(arrvieStation);
            connection.setStartTime(startTime);
            connection.setArriveTime(arriveTime);
            connection.setCostPrice(costPrice);

            if (A_STATION.equals(startStation) || B_STATION.equals(startStation)) {
                List<Node> toMettingNode = null;
                if (!toMettingMap.containsKey(startStation)) {
                    toMettingNode = new ArrayList<>();
                    toMettingMap.put(startStation, toMettingNode);
                } else {
                    toMettingNode = toMettingMap.get(startStation);
                }
                toMettingNode.add(connection);
            }

            if (A_STATION.equals(arrvieStation) || B_STATION.equals(arrvieStation)) {
                List<Node> arriveNode = null;
                if (!arriveMap.containsKey(arrvieStation)) {
                    arriveNode = new ArrayList<>();
                    arriveMap.put(arrvieStation, arriveNode);
                } else {
                    arriveNode = arriveMap.get(arrvieStation);
                }
                arriveNode.add(connection);
            }

        });
    }

    public long caculate() throws ParseException {
        List<Node> A2Metting = this.toMettingMap.get(A_STATION);
        List<Node> B2Metting = this.toMettingMap.get(B_STATION);
        if (A2Metting == null || A2Metting.size() == 0) {
            //A没法参会
            return 0;
        }

        if (B2Metting == null || B2Metting.size() == 0) {
            //B没法参会
            return 0;
        }

        // 剔除一部分航班  8点之前出发的  6点之后回家的航班

        long earlyStartTime = dateFormat.parse(currentDay + EARLY_METTING_TIME).getTime();
        long lastArriveTime = dateFormat.parse(currentDay + LAST_ARRIVE_TIME).getTime();
        List<Node> A2MettingCut = new ArrayList<>();
        for (Node node : A2Metting) {
            long arriveTimestamp = node.getArriveTime().getTime();
            long startTimestamp = node.getStartTime().getTime();
            if (startTimestamp >= earlyStartTime && lastArriveTime >= arriveTimestamp) {
                A2MettingCut.add(node);
            }
        }

        List<Node> B2MettingCut = new ArrayList<>();
        for (Node node : B2Metting) {
            long arriveTimestamp = node.getArriveTime().getTime();
            long startTimestamp = node.getStartTime().getTime();
            if (startTimestamp >= earlyStartTime && lastArriveTime >= arriveTimestamp) {
                B2MettingCut.add(node);
            }
        }

        // 确定可能的会议地点
        List<Metting> mayMetting = new ArrayList<>();
        A2MettingCut.forEach(node -> {
            String AarriveStation = node.getArriveStation();
            long aCost = node.getCostPrice();
            long aArriveTime = node.getArriveTime().getTime();
            for (Node bNode : B2MettingCut) {
                if (bNode.getArriveStation().equals(AarriveStation)) {
                    long bCost = bNode.getCostPrice();
                    long bArriveTime = bNode.getArriveTime().getTime();

                    Metting metting = new Metting();
                    metting.setStation(AarriveStation);
                    // 会议费用之和
                    metting.setTotalCost(aCost + bCost);


                    if (bArriveTime > aArriveTime) {
                        // b 后到
                        metting.setStartTime(bNode.getArriveTime());
                    } else {
                        //a 后到
                        metting.setStartTime(node.getArriveTime());
                    }
                    mayMetting.add(metting);
                }
            }
        });


        List<Node> aBack = this.arriveMap.get(A_STATION);
        List<Node> bBack = this.arriveMap.get(B_STATION);
        if (aBack == null || aBack.size() == 0) {
            //A没法回家
            return 0;
        }

        if (bBack == null || bBack.size() == 0) {
            //B没法回家
            return 0;
        }
        // 剔除回家航班
        // 剔除一部分航班  8点之前出发的  6点之后回家的航班
        List<Node> aBackCut = new ArrayList<>();
        aBack.forEach(node -> {
            long aBackTime = node.getArriveTime().getTime();
            if (aBackTime < lastArriveTime && aBackTime > earlyStartTime) {
                aBackCut.add(node);
            }
        });

        List<Node> bBackCut = new ArrayList<>();
        bBack.forEach(node -> {
            long bBackTime = node.getStartTime().getTime();
            if (bBackTime < lastArriveTime && bBackTime > earlyStartTime) {
                bBackCut.add(node);
            }
        });

        if (aBackCut == null || aBackCut.size() == 0) {
            //A没法回家
            return 0;
        }

        if (bBackCut == null || bBackCut.size() == 0) {
            //B没法回家
            return 0;
        }

        if (mayMetting == null || mayMetting.size() == 0) {
            //无法开会
            return 0;
        }

        //开会时间
        long $30min = 30 * 60 * 1000;
        List<Long> mayCost = new ArrayList<>();
        mayMetting.forEach(node -> {
            //开会地点
            String station = node.getStation();
            long fininshMetting = node.getStartTime().getTime() + $30min;

            // A 能回家，B也能回家，并且花费最少
            Map<String, Long> aCanBack = calculateMin(station, fininshMetting, aBack);
            Map<String, Long> bCanBack = calculateMin(station, fininshMetting, bBack);
            if (aCanBack.size() > 0 && bCanBack.size() > 0) {
                long total = aCanBack.get(station) + bCanBack.get(station) + node.getTotalCost();
                System.out.println(station + "--" + total);
                mayCost.add(total);
            }
        });

        if (mayCost.size() == 0) {
            // 这里没法回家，直接返回
            return 0;
        }

        Collections.sort(mayCost);

        return mayCost.get(0);

    }


    private Map<String, Long> calculateMin(String station, long finishDate, List<Node> back) {
        Map<String, Long> stationCost = new HashMap<>();
        back.forEach(node -> {
            if (node.getStartStation().equals(station) && node.getStartTime().getTime() >= finishDate) {
                long currentCost = node.getCostPrice();
                if (stationCost.containsKey(station)) {
                    Long originCost = stationCost.get(station);
                    if (originCost > currentCost) {
                        stationCost.put(station, currentCost);
                    }
                } else {
                    stationCost.put(station, currentCost);
                }

                System.out.println(node);
            }
        });
        return stationCost;
    }


    static class Metting {
        private String station;
        private Date startTime;
        private long totalCost;

        public String getStation() {
            return station;
        }

        public void setStation(String station) {
            this.station = station;
        }

        public Date getStartTime() {
            return startTime;
        }

        public void setStartTime(Date startTime) {
            this.startTime = startTime;
        }

        public long getTotalCost() {
            return totalCost;
        }

        public void setTotalCost(long totalCost) {
            this.totalCost = totalCost;
        }
    }

}
